﻿#include "board.h"
#include <QMouseEvent>
#include <QMessageBox>
#include "mainwindow.h"

const static int MARGIN_X = 32;//边缘宽
const static int MARGIN_Y = 32+20;//边缘高
const static int Grid_Width = 57;//格子宽度
const static int Radius = 28;//棋子半径

Board::Board(MainWindow* _mainWindow,QWidget *parent) : QWidget(parent)
{
    this->mainWindow=_mainWindow;
    init();
}

void Board::init()
{
    for (int i = 0; i < 32; i++)
        pieces[i].init(i);
    isRedTurn = true;
    selectId = -1;
    redStep=0;
    blackStep=0;
    mainWindow->updateStep(true,redStep);
    mainWindow->updateStep(false,blackStep);
}

void Board::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    //画棋盘
    painter.drawPixmap(0,20,521,577,QPixmap(":/./img/wood.jpg"));

    //画棋子
    for (int i = 0; i < 32; i++)
    {
        if(pieces[i].isAlive){
            int X=MARGIN_X+Grid_Width * (pieces[i].col-1)-Radius;
            int  Y=MARGIN_Y+Grid_Width * (pieces[i].row-1)-Radius;

            if(pieces[i].red){
                switch (pieces[i].type) {
                case Piece::KING:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RKS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RK.GIF"));
                    }

                    break;
                case Piece::CHE:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RRS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RR.GIF"));
                    }
                    break;
                case Piece::MA:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RNS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RN.GIF"));
                    }
                    break;
                case Piece::PAO:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RCS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RC.GIF"));
                    }
                    break;
                case Piece::XIANG:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RBS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RB.GIF"));
                    }
                    break;
                case Piece::SHI:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RAS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RA.GIF"));
                    }
                    break;
                case Piece::BING:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RPS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/RP.GIF"));
                    }
                    break;
                }

            }else{
                switch (pieces[i].type) {
                case Piece::KING:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BKS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BK.GIF"));
                    }
                    break;
                case Piece::CHE:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BRS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BR.GIF"));
                    }
                    break;
                case Piece::MA:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BNS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BN.GIF"));
                    }
                    break;
                case Piece::PAO:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BCS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BC.GIF"));
                    }
                    break;
                case Piece::XIANG:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BBS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BB.GIF"));
                    }
                    break;
                case Piece::SHI:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BAS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BA.GIF"));
                    }
                    break;
                case Piece::BING:
                    if (i == selectId){
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BPS.GIF"));
                    }else{
                        painter.drawPixmap(X,Y,Radius*2,Radius*2,QPixmap(":/./img/piece/BP.GIF"));
                    }
                    break;
                }
            }

        }else{
            int col=pieces[i].col;
            int row=pieces[i].row;
        }
    }
}

void Board::mouseReleaseEvent(QMouseEvent *event)
{
    int clickRow;
    int clickCol;
    QPoint pt = event->pos();
    if((pt.rx()-MARGIN_X)%Grid_Width<Radius){
        clickCol = (pt.rx()-MARGIN_X)/Grid_Width;
    }else{
        clickCol = (pt.rx()-MARGIN_X)/Grid_Width+1;
    }
    if((pt.ry()-MARGIN_Y)%Grid_Width<Radius){
        clickRow = (pt.ry()-MARGIN_Y)/Grid_Width;
    }else{
        clickRow = (pt.ry()-MARGIN_Y)/Grid_Width+1;
    }
    //    int clickRow = (event->pos().y()+r)/d, clickCol = (event->pos().x()+r)/d;
    clickCol++;
    clickRow++;
    if (clickRow < 1 || clickRow > 10 || clickCol < 1 || clickCol > 9)
        return;
    clickHandler(getPiece(clickRow, clickCol), clickRow, clickCol);
    update();
}

//判断该行列位置有没没棋子，有就返回ID，没有就返回-1
int Board::getPiece(int row, int col)
{
    for (int i = 0; i < 32; i++)
        if (row == pieces[i].row && col == pieces[i].col && pieces[i].isAlive)
            return i; //有棋子，返回棋子ID
    return -1; //该行列位置没棋子
}

void Board::clickHandler(int clickId, int row, int col)
{
    bool isGameOver=false;
    if (-1 == selectId && clickId >= 0 && pieces[clickId].red == isRedTurn) //没选过棋子，选择棋子
        selectId = clickId;
    else if (selectId >= 0) { //已经选中过了棋子
        if (clickId >= 0) { //点的是子
            if (pieces[clickId].red != pieces[selectId].red && canMove(selectId, row, col)) { //是对方棋子，且可走，吃子
                saveStep(selectId, row, col, clickId);
                pieces[clickId].isAlive = false;
                movePiece(selectId, row, col);
                selectId = -1;
                isGameOver=  checkWin();
            } else if (pieces[clickId].red == pieces[selectId].red) //是己方棋子，不需判断是否可走，无条件切换
                selectId = clickId;

        } else if (canMove(selectId, row, col)) { //点空位，且可走
            saveStep(selectId, row, col, clickId);
            movePiece(selectId, row, col);
            selectId = -1;
        }

        if(!isGameOver){
            mainWindow->resetTimer(true);
            if(isNetGame){
                if(!isRedTurn){
                    redStep++;
                }else{
                    blackStep++;
                }
                mainWindow->updateStep(true,redStep);
                mainWindow->updateStep(false,blackStep);
            }else{
                redStep++;
                mainWindow->updateStep(true,redStep);
            }

        }
    }



}

bool Board::canMove(int id, int row, int col)
{
    switch (pieces[id].type) {
    case Piece::KING:
        if (col > 3 && col < 7 &&
                ((pieces[id].red && row < 4 || !pieces[id].red && row > 7) && (abs(row - pieces[id].row) + abs(col - pieces[id].col) == 1)) //0+1=1
                || countAtLine(pieces[4].row, pieces[4].col, pieces[20].row, pieces[20].col) == 0)
            return true;
        break;
    case Piece::CHE:
        if (countAtLine(row, col, pieces[id].row, pieces[id].col) == 0)
            return true;
        break;
    case Piece::MA:
        if ( (abs(row-pieces[id].row)==1 && abs(col-pieces[id].col)==2 //左右跳
              && getPiece(pieces[id].row,(col+pieces[id].col)>>1) == -1 //没拐脚
              ) || (abs(row-pieces[id].row)==2 && abs(col-pieces[id].col)==1 //上下跳
                    && getPiece((row+pieces[id].row)>>1,pieces[id].col) == -1)) //没拐脚
            return true;
        break;
    case Piece::PAO:
        if (getPiece(row, col) == -1 && countAtLine(row, col, pieces[id].row, pieces[id].col) == 0 //移动
                || getPiece(row, col) != -1 && countAtLine(row, col, pieces[id].row, pieces[id].col) == 1) //吃子
            return true;
        break;
    case Piece::XIANG:
        if ((pieces[id].red && row < 6 || !pieces[id].red && row > 5) //没过河
                && abs(row - pieces[id].row) == 2 && abs(col - pieces[id].col) == 2 //象步
                && getPiece((row+pieces[id].row)>>1, (col+pieces[id].col)>>1) == -1 ) //没象眼
            return true;
        break;
    case Piece::SHI:
        if (col > 3 && col < 7 && (pieces[id].red && row < 4 || !pieces[id].red && row > 7)
                && abs(row - pieces[id].row) == 1 && abs(col - pieces[id].col) == 1)
            return true;
        break;
    case Piece::BING:
        if (abs(row - pieces[id].row) + abs(col - pieces[id].col) != 1)
            break;
        if (pieces[id].red) { //红棋在上
            if (row < pieces[id].row) break;
            if (pieces[id].row < 6 && row == pieces[id].row) break;
        } else { //黑棋在下
            if (row > pieces[id].row) break;
            if (pieces[id].row > 5 && row == pieces[id].row) break;
        }
        return true;
    }
    return false;
}

//统计直线上棋子个数
int Board::countAtLine(int row1, int col1, int row2, int col2)
{
    int min, max, cnt = 0;
    if (row1 != row2 && col1 != col2)
        return -1;
    if (row1 == row2) {
        if (col1 < col2) {
            min = col1;
            max = col2;
        } else {
            min = col2;
            max = col1;
        }
        for (int col = min+1; col < max; col++)
            if (getPiece(row1, col) >= 0)
                cnt++;
    } else if (col1 == col2) {
        if (row1 < row2) {
            min = row1;
            max = row2;
        } else {
            min = row2;
            max = row1;
        }
        for (int row = min+1; row < max; row++)
            if (getPiece(row, col1) >= 0)
                cnt++;
    }
    return cnt;
}

void Board::movePiece(int id, int row, int col)
{
    pieces[id].row = row;
    pieces[id].col = col;
    //    selectId = -1;
    isRedTurn = !isRedTurn;
}

void Board::saveStep(int fromId, int rowTo, int colTo, int targetId)
{
    Step *step = new Step;
    step->rowFrom = pieces[fromId].row;
    step->colFrom = pieces[fromId].col;
    step->rowTo = rowTo;
    step->colTo = colTo;
    step->fromId = fromId;
    step->toId = targetId;
    steps.append(step);
}

bool Board::checkWin()
{
    if (!pieces[4].isAlive) {
        QMessageBox::information(this, "Game Over", "Black Win");
        steps.clear();
        mainWindow->resetTimer(true);
        init();
    } else if (!pieces[20].isAlive) {
        QMessageBox::information(this, "Game Over", "Red Win");
        steps.clear();
        mainWindow->resetTimer(true);
        init();
    }
}
void Board::backOne()
{
    if(steps.size() == 0) return;

    Step* step = steps.last();

    if (step->toId >= 0)
        pieces[step->toId].isAlive = true;
    movePiece(step->fromId, step->rowFrom, step->colFrom);

    steps.removeLast();

    update();
    delete step;
}

void Board::undoBoard()
{
   int ret= QMessageBox::information(this,
                             tr("information"),tr("Are you sure you regret chess?"),
                             QMessageBox::Ok|QMessageBox::Cancel,
                             QMessageBox::Ok);
    if(ret==QMessageBox::Ok){
        backOne();
        backOne();
    }
}

void Board::resetBoard()
{
    steps.clear();
    init();
    repaint();
}

void Board::backGame()
{
    mainWindow->close();
    MainWindow* newMainWindow = new MainWindow;
    newMainWindow->resize(520+260,576+20*2);
    newMainWindow->show();
}

void Board::timeout(int value)
{
    QMessageBox::information(this,
                             tr("information"),tr("Timeout,Game Over"),
                             QMessageBox::Ok | QMessageBox::Cancel,
                             QMessageBox::Ok);
}
